#ifndef __M_FMT_H__
#define __M_FMT_H__

#include "level.hpp"
#include "message.hpp"
#include <time.h>
#include <vector>
#include <cassert>
#include <sstream>

namespace mylog{
  class FormatItem{
       public:
         using ptr = std::shared_ptr<FormatItem>;
         virtual ~FormatItem() {}
         virtual void format(std::ostream &out, const mylog::LogMsg &msg) = 0;
  };
  
  //基于基类，派生出不同的格式化子项子类，主体消息，日志等级，时间子项，文件名，行号，日志器名称，线程ID，制表符，换行，其它
  class MsgFormatItem : public FormatItem{
       public:
         MsgFormatItem(const std::string &str = "") {}
         virtual void format(std::ostream &out, const mylog::LogMsg &msg) override{
            out << msg._payload; 
         }
  };
  class LevelFormatItem : public FormatItem{
       public:
         LevelFormatItem(const std::string &str = "") {}
         virtual void format(std::ostream &out, const mylog::LogMsg &msg) override{
            out << LogLevel::Tostring(msg._level); 
         }

  };
  class NameFormatItem : public FormatItem{
       public:
         NameFormatItem(const std::string &str = "") {}
         virtual void format(std::ostream &out, const mylog::LogMsg &msg) override{
            out << msg._name; 
         }
  
  };
  class ThreadFormatItem : public FormatItem{
       public:
         ThreadFormatItem(const std::string &str = "") {}
         virtual void format(std::ostream &out, const mylog::LogMsg &msg) override{
            out << msg._tid; 
         }

  };
  class TimeFormatItem : public FormatItem{
    private:
         std::string _format;
    public:
         TimeFormatItem(const std::string &format = "%H:%M:%S"):_format(format) {}
         virtual void format(std::ostream &out, const mylog::LogMsg &msg) override{
            time_t t = msg._ctime;
            struct tm lt;
            localtime_r(&t, &lt);
            char tmp[128];
            strftime(tmp, 127, _format.c_str(), &lt);
            out << tmp;
         }
  }; 
  class CFileFormatItem : public FormatItem{
       public:
         CFileFormatItem(const std::string &str = "") {}
         virtual void format(std::ostream &out, const mylog::LogMsg &msg) override{
            out << msg._file; 
         }
  
  };
  class CLineFormatItem : public FormatItem{
       public:
         CLineFormatItem(const std::string &str = "") {}
         virtual void format(std::ostream &out, const mylog::LogMsg &msg) override{
            out << msg._line; 
         }
  
  };
  class TabFormatItem : public FormatItem{
       public:
         TabFormatItem(const std::string &str = "") {}
         virtual void format(std::ostream &out, const mylog::LogMsg &msg) override{
            out << "\t"; 
         }

  };

  class NLineformatItem : public FormatItem{
       public:
         NLineformatItem(const std::string &str = "") {}
         virtual void format(std::ostream &out, const mylog::LogMsg &msg) override{
            out << "\n"; 
         }
  };
  class OtherFormatItem : public FormatItem{
    private:
         std::string _str;
    public:
         OtherFormatItem(const std::string &str = ""):_str(str) {}
         virtual void format(std::ostream &out, const mylog::LogMsg &msg) override{
            out << _str; 
         }

  };

  class Formatter{
    public:
      using ptr = std::shared_ptr<Formatter>;
      Formatter(const std::string &pattern = "[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n"):
        _pattern(pattern){
           assert(parsePattern()); //解析失败。直接报错
        }
      std::ostream& format(std::ostream &out, const mylog::LogMsg &msg){
        for(auto &it:_item)
          it->format(out, msg);
        return out;
      }
      std::string format(const mylog::LogMsg &msg){
           std::stringstream ss;
           for (auto &it:_item)
             it->format(ss, msg);
           return ss.str();
      }
    private:
      bool parsePattern(){
        //1.对格式化字符串进行解析
        //ab%%cde[%d{%H:%M:%S}][%P]%T%m%n
        std::vector<std::pair<std::string, std::string>> fmt_order;
        size_t pos = 0;
        std::string key,val;
        while(pos < _pattern.size())
        {
          //ab
          if(_pattern[pos] != '%'){
              val.push_back(_pattern[pos++]);
              continue;
          }
          //能走下来代表此时位置就为%，处理%%
          if(pos + 1 < _pattern.size() && _pattern[pos + 1] == '%'){
             val.push_back('%');
             pos += 2;
             continue;
          }
          //假如%后面是一个格式化字符，比如说d，则说明原始字符串处理完毕，可以直接创建对象
          if(val.empty() == false){
               fmt_order.push_back(std::make_pair("", val));
               val.clear();
          }
          
          pos += 1;  //此时指向的就是格式化字符，如d
          if(pos == _pattern.size()){
            std::cout << "%之后没有对应的格式化字符！\n";
            return false;
          }

          key = _pattern[pos];
          pos += 1;
          //处理{}问题
          if(pos < _pattern.size() && _pattern[pos] == '{'){
              pos += 1;  //指向{之后的位置
              while(pos < _pattern.size() && _pattern[pos] != '}'){
                val.push_back(_pattern[pos++]);  //假如没有遇到花括号，说明还是子串，压入val中
              }

              //如果走到末尾，说明没有右花括号，格式错误
              if(pos == _pattern.size()) {
                std::cout << "子规则格式错误！\n";
                return false;
              }
              pos += 1;
          }
          //添加处理结果
          fmt_order.push_back(std::make_pair(key, val));
          key.clear();
          val.clear();

        }
        //2.根据解析到的字符初始化格式化子项数组成员
          for (auto &it:fmt_order){
            _item.push_back(createItem(it.first, it.second));
          }
          return true;
      }

      FormatItem::ptr createItem(const std::string &key, const std::string &val){
        if(key == "d")  return std::make_shared<TimeFormatItem>(val);
        if(key == "t")  return std::make_shared<ThreadFormatItem>();
        if(key == "c")  return std::make_shared<NameFormatItem>();
        if(key == "f")  return std::make_shared<CFileFormatItem>();
        if(key == "l")  return std::make_shared<CLineFormatItem>();
        if(key == "p")  return std::make_shared<LevelFormatItem>();
        if(key == "T")  return std::make_shared<TabFormatItem>();
        if(key == "m")  return std::make_shared<MsgFormatItem>();
        if(key == "n")  return std::make_shared<NLineformatItem>();
        if(key == "")   return std::make_shared<OtherFormatItem>(val);
        //假如key不为空，但又没有匹配对应的值，说明不存在该格式化字符，直接报错
        std::cout << "不存在对应的格式化字符%" << key << std::endl;
        abort();
        return FormatItem::ptr();
      }
    private:
      std::string _pattern;
      std::vector<FormatItem::ptr> _item;
  };

}



#endif
